﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Forms.Integration;
using System.Windows.Interop;
using System.Windows.Media;

namespace FxFlowWindowBase.Win.Helper
{
	public class FlowWin
	{

		// 流动窗体类
		internal FlowWindow Window { get; set; }


		private FlowWin(FlowWindow window)
		{
			this.Window = window;
		}

		/// <summary>
		/// 调用该方法，由主线程更新界面
		/// </summary>
		/// <param name="dele">更新界面的操作</param>
		public void UpdateWin(Action dele)
		{
			Window?.Dispatcher.Invoke(dele);
		}


		public virtual void SetControlColor(Control ele, string color, int type)
		{
			if (ele == null)
			{
				throw new NullReferenceException("指定的控件不应该是null");
			}
			UpdateWin(() =>
			{
				if (type > 0)
				{
					ele.Foreground = new SolidColorBrush(FlowWindow.ParseColorStr(color));
				}
				else
				{
					ele.Background = new SolidColorBrush(FlowWindow.ParseColorStr(color));
				}
			});
		}


		public virtual void ProgressbarToSmooth(ProgressBar pb, int val)
		{
			if (pb == null) return;
			if (val < 0) val = 0;
			if (val > 100) val = 100;
			double pbVal = 0;
			UpdateWin(() =>
			{
				pbVal = pb.Value;
			});
			if (val > pbVal)
			{
				for (int i = (int)pbVal; i <= val; i++)
				{
					UpdateWin(() =>
					{
						pb.Value = i;
					});
					Thread.Sleep(100);
				}
			}
			else
			{
				for (int i = (int)pbVal; i >= val; i--)
				{
					UpdateWin(() =>
					{
						pb.Value = i;
					});
					Thread.Sleep(100);
				}
			}
		}


		public virtual void SetControlClickEvent(Control control, Action<string> clickAction)
		{
			if (control == null)
			{
				throw new NullReferenceException("指定的控件不应该是null");
			}

			if (clickAction == null)
			{
				throw new NullReferenceException("添加的事件不能为null");
			}

			if ((control is ButtonBase) == false)
			{
				throw new ArgumentException("该控件不可添加点击事件!");
			}
			(control as ButtonBase).Click += (sender, args) =>
			{
				clickAction.Invoke((sender as ButtonBase).Name);
			};
		}


		public virtual void SetControlDbClick(Control control, Action<string> dbClickAction)
		{
			if (control == null)
			{
				throw new NullReferenceException("指定的控件不应该是null");
			}

			if (dbClickAction == null)
			{
				throw new NullReferenceException("添加的事件不能为null");
			}

			control.MouseDoubleClick += (sender, args) =>
			{
				dbClickAction.Invoke((sender as Control).Name);
			};
		}


		public virtual void SetKeyDownEvent(Control control, Action<int> keyEvent)
		{
			if (control == null)
			{
				throw new NullReferenceException("指定的控件不应该是null");
			}

			if (keyEvent == null)
			{
				throw new NullReferenceException("添加的事件不能为null");
			}

			control.KeyDown += (sender, args) =>
			{
				keyEvent.Invoke((int)args.Key);
			};
		}


		public virtual void SetControlTextAlign(UIElement control, int align)
		{
			if (control == null)
			{
				throw new NullReferenceException("指定的控件不应该是null");
			}
			TextAlignment alignment;
			switch (align)
			{
				case 0:
					alignment = TextAlignment.Left;
					break;
				case 1:
					alignment = TextAlignment.Center;
					break;
				case 2:
					alignment = TextAlignment.Right;
					break;
				default:
					alignment = TextAlignment.Justify;
					break;
			}
			if (control is TextBox tb)
			{
				tb.TextAlignment = alignment;
				return;
			}
			else if (control is TextBlock tbx)
			{
				tbx.TextAlignment = alignment;
			}
			else if (control is Button btn)
			{
				btn.HorizontalContentAlignment = (HorizontalAlignment)(int)alignment;
			}
			else
			{
				throw new ArgumentException("该控件不可设置文字对齐方式!");
			}
		}

		public static FlowWin NewWindow(int width, int height, double opticity)
		{
			FlowWindow flowWindow = new FlowWindow()
			{
				Width = width,
				Height = height,
				Opacity = opticity
			};
			return new FlowWin(flowWindow);
		}


		public static FlowWin NewWindow()
		{
			FlowWindow flowWindow = new FlowWindow();
			return new FlowWin(flowWindow);
		}


		/// <summary>
		/// 判断该类window是否被实例化，若没有则抛出异常
		/// </summary>
		private void AssertFlowWinIsNull()
		{
			if (Window == null)
			{
				throw new Exception("您还未初始化流动窗体,请先初始化!");
			}
		}

		/// <summary>
		/// 获取窗口句柄
		/// </summary>
		/// <returns>窗口句柄</returns>
		public virtual int GetWindowHandle()
		{
			AssertFlowWinIsNull();
			return new WindowInteropHelper(Window).Handle.ToInt32();
		}

		public virtual FlowWin Topmost(bool allTop)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.Topmost = allTop;
			});
			return this;
		}

		public virtual FlowWin AutoScrollToEnd(bool scroll = true)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AutoScrollToEnd = scroll;
			});
			return this;
		}

		public virtual FlowWin SetPos(double x, double y)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.Left = x;
				Window.Top = y;
			});
			return this;
		}

		public virtual FlowWin SetCanResize(bool resizeable)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.ResizeMode = resizeable ? ResizeMode.CanResizeWithGrip : ResizeMode.NoResize;
			});
			return this;
		}

		public virtual FlowWin SetPosCenterInScreen()
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
			});
			return this;
		}

		public virtual FlowWin SetSize(double width, double height)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.Width = width;
				Window.Height = height;
			});
			return this;
		}

		public virtual FlowWin SetTitle(string title)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.Title = title;
			});
			return this;
		}

		public virtual FlowWin SetOpcity(double opcity)
		{
			AssertFlowWinIsNull();
			if (opcity < 0) opcity = 0;
			if (opcity > 1) opcity = 1;
			UpdateWin(() =>
			{
				Window.Opacity = opcity;
			});
			return this;
		}

		public virtual FlowWin SetBackColor(string color)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.SetBackColor(color);
			});
			return this;
		}

		public virtual FlowWin SetOnCloseEvent(Action onClose)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.SetOnCloseEvent(onClose);
			});
			return this;
		}

		public virtual FlowWin SetOnBeforeCloseEvent(Func<bool> onBoforeClose)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.SetOnBeforeCloseEvent(onBoforeClose);
			});
			return this;
		}

		public virtual FlowWin SetOnClosedEvent(Action onClosedEvent)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.SetOnClosedEvent(onClosedEvent);
			});
			return this;
		}

		public virtual FlowWin AddText(string name, string text, string color, string backColor, int alignType)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AddText(name, text, color, backColor, alignType);
			});
			return this;
		}

		public virtual FlowWin AddText(string name, string text, int alignType)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AddText(name, text, "#FFFF00", "#77000000", alignType);
			});
			return this;
		}

		public virtual FlowWin AddCombox(string name, object[] items, Action<string, int, string> onChange)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AddCombox(name, "blue", "#100", items, onChange);
			});
			return this;
		}

		public virtual FlowWin AddCombox(string name, string foreColor, string backColor, object[] items, Action<string, int, string> onChange)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AddCombox(name, foreColor, backColor, items, onChange);
			});
			return this;
		}

		public virtual FlowWin AddButton(string name, string text, string foreColor, string backColor, Action<string> clickEvent)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AddButton(name, text, foreColor, backColor, 1, clickEvent);
			});
			return this;
		}

		public virtual FlowWin AddButton(string name, string text, Action<string> clickEvent)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AddButton(name, text, "#FFFF00", "#77000000", 1, clickEvent);
			});
			return this;
		}

		public virtual FlowWin AddTextbox(string name, string defaultText, string foreColor, string backColor, Action<string> textChangeAction)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AddTextbox(name, defaultText, foreColor, backColor, textChangeAction);
			});
			return this;
		}


		public virtual FlowWin AddTextbox(string name, string defaultText)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AddTextbox(name, defaultText, "#FFFF00", "#77000000", null);
			});
			return this;
		}

		public virtual FlowWin AddProgressbar(string name, int defaultVal, string foreColor, string backColor, Action<double> valueChange)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AddProgressbar(name, defaultVal, foreColor, backColor, valueChange);
			});
			return this;
		}

		public virtual FlowWin AddProgressbar(string name, int val)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AddProgressbar(name, val, "red", "black", null);
			});
			return this;
		}

		public virtual FlowWin AddSlider(string name, int defaultVal, string foreColor, string backColor, Action<double, double> dragEvent)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AddSlider(name, defaultVal, foreColor, backColor, dragEvent);
			});
			return this;
		}

		public virtual FlowWin AddSlider(string name, int defaultVal, Action<double, double> dragEvent)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AddSlider(name, defaultVal, "red", "black", dragEvent);
			});
			return this;
		}

		public virtual FlowWin AddCheckbox(string name, string text, bool defaultVal, string foreColor, string backColor, Action<bool, string> valueChange)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AddCheckbox(name, text, defaultVal, foreColor, backColor, valueChange);
			});
			return this;
		}

		public virtual FlowWin AddCheckbox(string name, string text, bool defaultVal)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.AddCheckbox(name, text, defaultVal, "yellow", "#77000000", null);
			});
			return this;
		}

		/// <summary>
		/// 添加一个自定义组件，不建议在脚本环境中使用，建议在扩展环境中调用
		/// </summary>
		/// <param name="element">待添加的组件</param>
		/// <returns>自身</returns>
		public virtual FlowWin AddControl<T>(T element, Action<T> onElementInit) where T : UIElement
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				onElementInit?.Invoke(element);
				Window.AddControl(element);
			});
			return this;
		}

		/// <summary>
		/// 添加一个自定义组件，不建议在脚本环境中使用，建议在扩展环境中调用(适用于有一个公开空参构造方法的组件)
		/// </summary>
		/// <param name="onElementInit">初始化事件</param>
		/// <returns>自身</returns>
		public virtual FlowWin AddControl<T>(Action<T> onElementInit) where T : UIElement
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Type type = typeof(T);
				ConstructorInfo constructor = type.GetConstructor(new Type[0]);
				T control = constructor.Invoke(new object[0]) as T;
				onElementInit?.Invoke(control);
				Window.AddControl(control);
			});
			return this;
		}

		/// <summary>
		/// 设置底边栏
		/// </summary>
		/// <typeparam name="T">底测控件类型</typeparam>
		/// <param name="onElementInit">初始化事件</param>
		/// <returns>自身</returns>
		public virtual FlowWin SetFooterBar<T>(Action<T> onElementInit) where T : UIElement
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Type type = typeof(T);
				ConstructorInfo constructor = type.GetConstructor(new Type[0]);
				T control = constructor.Invoke(new object[0]) as T;
				onElementInit?.Invoke(control);
				Window.SetFooterBar(control);
				Window.SwitchFooterBarState(Visibility.Visible);
			});
			return this;
		}

		/// <summary>
		/// 设置底边栏显示状态
		/// </summary>
		/// <param name="isShow">是否显示</param>
		/// <returns>自身</returns>
		public virtual FlowWin SetFooterBarShowState(bool isShow)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.SwitchFooterBarState(isShow ? Visibility.Visible : Visibility.Collapsed);
			});
			return this;
		}

		/// <summary>
		/// 替换页面一个已有的控件，不建议在脚本环境中使用，建议在扩展环境中调用
		/// </summary>
		/// <param name="name">原本控件名</param>
		/// <param name="newElement">新控件</param>
		/// <returns>自身</returns>
		public virtual FlowWin ReplaceControl(string name, UIElement newElement)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.ReplaceControl(name, newElement);
			});
			return this;
		}

	public virtual object FindViewByName(string name)
		{
			AssertFlowWinIsNull();
			object element = null;
			UpdateWin(() =>
			{
				element = Window.FindViewByName(name);
			});
			return element;
		}

		public virtual List<object> FindViewByRegex(string regex)
		{
			AssertFlowWinIsNull();
			List<object> elements = null;
			UpdateWin(() =>
			{
				elements = Window.FindViewByRegex(regex);
			});
			return elements;
		}

		public virtual FlowWin RemoveChild(string name)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.RemoveControl(name);
			});
			return this;
		}

		public virtual FlowWin RemoveChildByRegex(string regex)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.RemoveControlsByRegex(regex);
			});
			return this;
		}

		public virtual FlowWin RemoveAllChild()
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.RemoveAllControl();
			});
			return this;
		}

		public virtual FlowWin ShowLoading(string msg)
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.ShowLoading(msg);
			});
			return this;
		}

		public virtual FlowWin CloseLoading()
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.CloseLoading();
			});
			return this;
		}


		public virtual FlowWin Show()
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				ElementHost.EnableModelessKeyboardInterop(Window);
				Window.Show();
			});
			return this;
		}

		public virtual FlowWin Hide()
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.Hide();
			});
			return this;
		}

		public virtual void Close()
		{
			AssertFlowWinIsNull();
			UpdateWin(() =>
			{
				Window.Close();
			});
		}
	}
}
